#include "Epoll.h"

int create_socket(const char* ip, int port) {
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        return -1;
    }

    // 绑定和监听...
    struct sockaddr_in laddr;
    laddr.sin_family = AF_INET;
    laddr.sin_port   = htons(port);
    inet_pton(AF_INET, ip, &laddr.sin_addr);

    // 设置地址重用
    int optval = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
        perror("setsockopt");
        return -1;
    }

    if (bind(server_fd, (struct sockaddr*)&laddr, sizeof(laddr)) < 0) {
        perror("bind");
        return -1;
    }

    if (listen(server_fd, 200) < 0) {
        perror("listen");
        return -1;
    }
    return server_fd;
}

void client_callback(Epoll_t* epoll, int fd) {
    // 有数据可读
    char    buffer[BUFFER_SIZE];
    ssize_t num_bytes = read(fd, buffer, BUFFER_SIZE);
    if (num_bytes > 0) {
        printf("Received from %d: %.*s\n", fd, (int)num_bytes, buffer);

        // 回复客户端
        write(fd, buffer, num_bytes);
    }
    else if (num_bytes == 0) {
        // 客户端关闭连接
        printf("Client closed the connection.\n");

        // 关闭连接并从 epoll 实例中移除
        epoll_remove_item(epoll, fd);
        close(fd);
    }
    else {
        perror("read");
        exit(1);
    }
}

void server_callback(Epoll_t* epoll, int fd) {
    struct sockaddr_in client_addr;
    socklen_t          client_len;
    char               buffer[BUFFER_SIZE];

    // 有新的连接
    client_len  = sizeof(client_addr);
    int conn_fd = accept(fd, (struct sockaddr*)&client_addr, &client_len);
    if (conn_fd == -1) {
        perror("accept");
        exit(1);
    }
    epoll_add_item(epoll, conn_fd, client_callback);

    printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
}

int main() {
    // 创建套接字
    int server_fd = create_socket("0.0.0.0", SERVERPORT);
    if (server_fd == -1)
        exit(-1);

    Epoll_t epoll;
    
    epoll_init(&epoll);
    epoll_add_item(&epoll, server_fd, server_callback);
    epoll_exec(&epoll);

    // 关闭套接字
    close(server_fd);

    return 0;
}
